feat(filesystem): add append_file and write_or_update_file tools#2816
feat(filesystem): add append_file and write_or_update_file tools#2816agn-7 wants to merge 10 commits intomodelcontextprotocol:mainfrom
Conversation
|
Hi I really need this feature. could you please take a look? |
This commit adds two new tools to the filesystem server: 1. **append_file**: Appends content to the end of an existing file. - File must already exist - Preserves existing content, adds new content at the end 2. **write_or_update_file**: Creates a new file or appends to an existing file. - If file doesn't exist: creates it with the provided content - If file exists: appends new content to the end - Useful when you want to add content while preserving existing data Changes include: - Added `appendFileContent` and `writeOrUpdateFileContent` functions to lib.ts - Added tool registrations and schemas to index.ts - Updated README.md with new tool documentation - Added comprehensive tests for the new functions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
d4d0d52 to
d15eb75
Compare
|
I just resolved the merge conflicts in my previously submitted PR. Could you please review it to help prevent future conflicts? |
|
@claude review |
|
Claude finished @cliffhall's task in 1m 43s —— View job PR Review: feat(filesystem): add append_file and write_or_update_file tools
Thanks for this PR, @agn-7. The feature direction is sound — there's a real gap between "always overwrite" and "no append option." A few issues need addressing before merge. Critical Issues1. Memory-inefficient read-modify-write in Both new functions read the entire file into memory, concatenate, then write atomically. For their stated use case (log files, incrementally-built documents), this is O(n) memory in file size — exactly where you'd expect large files. Node's export async function appendFileContent(filePath: string, content: string): Promise<void> {
try {
await fs.access(filePath);
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
throw new Error(`File does not exist: ${filePath}`);
}
throw error;
}
await fs.appendFile(filePath, content, 'utf-8');
}The existing atomic-rename pattern in 2. TOCTOU race between The check-then-act pattern is inherently racy. Cleaner approach — just attempt the read directly: let existingContent: string;
try {
existingContent = await readFileContent(filePath);
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
throw new Error(`File does not exist: ${filePath}`);
}
throw error;
}This eliminates the race and removes a redundant syscall. 3. Unreliable const message = stats.birthtime.getTime() === stats.mtime.getTime()
? `Successfully created ${args.path} with content`
: `Successfully appended content to ${args.path}`;After an atomic const existed = await fs.access(validPath).then(() => true).catch(() => false);
await writeOrUpdateFileContent(validPath, args.content);
const message = existed
? `Successfully appended content to ${args.path}`
: `Successfully created ${args.path} with content`;Design Issues4. Code duplication ( The if (fileExists) {
await appendFileContent(filePath, content);
} else {
await writeFileContent(filePath, content);
}5. Semantics of "Update" typically implies overwriting or modifying existing content. The actual behavior here is "create or append," which may surprise users who interpret "update" as replacing content. Consider Minor Issues6. Three identical Zod schemas (
7. Tests verify mock calls, not behavior The new tests (e.g., What Looks Good
|
- Use fs.appendFile directly instead of read-modify-write (O(1) memory) - Eliminate TOCTOU race between fs.access and fs.readFile - Replace unreliable birthtime===mtime heuristic with pre-op existence check - Have writeOrUpdateFileContent delegate to appendFileContent (no duplication) - Consolidate three identical Zod schemas into one PathContentArgsSchema Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Pushed 54ed837 addressing the review. Per-item response: 1. Memory-inefficient read-modify-write — fixed. 2. TOCTOU race — fixed. Removed the 3. Unreliable 4. Code duplication — fixed. 6. Three identical Zod schemas — consolidated into 5. 7. Mock-based tests — left as-is, per the reviewer's note that this matches the existing style. Tests were updated to reflect the new direct- |
…_file Renames the tool, schema, and underlying function to accurately describe the behavior (create-or-append, not update/overwrite) per review feedback. - Tool: write_or_update_file -> create_or_append_file - Schema: WriteOrUpdateFileArgsSchema -> CreateOrAppendFileArgsSchema - Function: writeOrUpdateFileContent -> createOrAppendFileContent - README updated; tests updated; append_file description updated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Follow-up on item 5: rename applied in ebc44b2.
|
Description
Fixes #2807
Added two new tools to the filesystem MCP server for enhanced file modification capabilities:
append_file: Appends content to existing files without overwritingwrite_or_update_file: Creates new files or appends to existing ones (smart create-or-append)These tools complement the existing
write_filetool by providing non-destructive file operations, addressing the common use case where users want to add content to files while preserving existing data.Server Details
Motivation and Context
The existing
write_filetool always overwrites file content, which is problematic when users want to:These new tools solve this by providing:
How Has This Been Tested?
Breaking Changes
No breaking changes. These are new tools that don't affect existing functionality.
Types of changes
Checklist
Additional context
Implementation details: